//
//  SunriseSensor.m
//  Pennyworth
//
//  Equations taken from http://www.srrb.noaa.gov/highlights/sunrise/solareqns.PDF
//  Created by Chris Karr on 6/16/08.
//  Copyright 2008 Chris Karr. All rights reserved.
//

#import "SunriseSensor.h"
#import "Context.h"
#import "SensorsController.h"

#include "math.h"

#define SENSOR_NAME @"Daylight"

@implementation SunriseSensor

- (CGFloat) fractionalYear
{
	NSCalendarDate * now = [NSCalendarDate date];
	
	return ((2 * M_PI) / 365) * (((CGFloat) [now dayOfYear]) - 1 + ((((CGFloat) [now hourOfDay]) - 12) / 24));
}

- (CGFloat) eqTime
{
	CGFloat fractYear = [self fractionalYear];
	
	CGFloat et = 229.18 * (0.000075 + (0.001868 * cos (fractYear)) - (0.032077 * sin (fractYear)) - 
						   (0.014615 * cos (2 * fractYear)) - (0.040849 * sin (2 * fractYear)));
	
	return et;
}

- (CGFloat) solarDeclination
{
	CGFloat fractYear = [self fractionalYear];
	
	CGFloat decl = 0.006918 - (0.399912 * cos (fractYear)) + (0.070257 * sin (fractYear)) - (0.006758 * cos (2 * fractYear)) +
		   (0.000907 * sin (2 * fractYear)) - (0.002697 * cos (3 * fractYear)) + (0.00148 * sin (3 * fractYear));
	
	return decl;
}

- (CGFloat) radiansForDegrees:(CGFloat) degrees
{
	return (M_PI / 180.0) * degrees;
}

- (CGFloat) degreesForRadians:(CGFloat) rads
{
	return (180 / M_PI) * rads;
}

- (CGFloat) hourAngleForLatitude:(CGFloat) lat longitude:(CGFloat) lon
{
	CGFloat decl = [self solarDeclination];
	
	CGFloat ha =  acos ((cos ([self radiansForDegrees:90.833]) / (cos ([self radiansForDegrees:lat]) * cos (decl))) - 
						(tan ([self radiansForDegrees:lat]) * tan (decl)));
	
	return ha;
}

- (CGFloat) sunriseForLatitude:(CGFloat) lat longitude:(CGFloat) lon
{
	return 720 + (4 * (lon - [self degreesForRadians:[self hourAngleForLatitude:lat longitude:lon]])) - [self eqTime];
}

- (CGFloat) sunsetForLatitude:(CGFloat) lat longitude:(CGFloat) lon
{
	return 720 + (4 * (lon + [self degreesForRadians:[self hourAngleForLatitude:lat longitude:lon]])) - [self eqTime];
}

- (CGFloat) solarNoonForLatitude:(CGFloat) lat longitude:(CGFloat) lon
{
	return 720 + (4 * lon) - [self eqTime];
}

- (void) awakeFromNib
{
	[[SensorsController sharedController] addSensor:SENSOR_NAME];

	location = malloc (sizeof (MachineLocation));

	timer = [[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain];
	[timer fire];
}

- (void) dealloc
{
	[timer invalidate];
	[timer release];
	
	free (location);
	
	[super dealloc];
}

- (void) update:(NSTimer *) theTimer
{
	if (![[SensorsController sharedController] canFire:SENSOR_NAME])
	{
		NSMutableDictionary * note = [NSMutableDictionary dictionary];
		[note setValue:SENSOR_NAME forKey:OBSERVATION_SENSOR];
		[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];
		
		return;
	}		

	ReadLocation (location);

	NSTimeZone * myTimeZone = [NSTimeZone localTimeZone];

	CGFloat latitude = 90 * FractToFloat (location->latitude);
	CGFloat longitude = -90 * FractToFloat (location->longitude);
		
	CGFloat utcSunrise = [self sunriseForLatitude:latitude longitude:longitude] + ([myTimeZone secondsFromGMT] / 60);
	CGFloat utcSunset = [self sunsetForLatitude:latitude longitude:longitude]  + ([myTimeZone secondsFromGMT] / 60);
		
	NSCalendarDate * now = [NSCalendarDate date];
	NSUInteger nowMinutes = ([now hourOfDay] * 60) + [now minuteOfHour];

	NSMutableDictionary * note = [NSMutableDictionary dictionary];
	
	[note setValue:@"Daylight Sensor" forKey:OBSERVATION_SENSOR];
	
	if (nowMinutes > utcSunrise && nowMinutes < utcSunset)
		[note setValue:@"Day" forKey:OBSERVATION_OBSERVATION];
	else
		[note setValue:@"Night" forKey:OBSERVATION_OBSERVATION];

	[note setValue:[NSNumber numberWithInteger:300] forKey:OBSERVATION_LIFESPAN];
	
	[[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note];
}

@end
